﻿using System.Collections.Generic;
using NHibernate;
using NHibernate.Criterion;
using NhJump.Persistence.Context;
using NhJump.Persistence.Model;
using NhJump.Persistence.Querying.Definition;
using NhJump.Persistence.Querying.Executable;

namespace NhJump.Persistence
{
    /// <summary>
    /// Implementation of IRepository for NHibernate
    /// </summary>
    public class NHibernateRepository<T, TIdentifier> : IRepository<T, TIdentifier>
        where T : IRootAggregateDomainEntity<TIdentifier>
    {
        public IUnitOfWork UnitOfWork { get; private set; }

        public NHibernateRepository(IUnitOfWork unitOfWork)
        {
            UnitOfWork = unitOfWork;
        }

        public NHibernateRepository()
            : this(UnitOfWorkLocator.Current)
        {
        }

        public void SaveOrUpdate(T entity)
        {
            UnitOfWork.Session.SaveOrUpdate(entity);
        }


        public void AttachUnchanged(T persistent)
        {
            UnitOfWork.Session.Lock(persistent, LockMode.None);
        }

        public void Delete(T forDeletion)
        {
            UnitOfWork.Session.Delete(forDeletion);
        }

        public IExecutableQuery<T, TIdentifier> ById(TIdentifier id)
        {
            return new CriteraQueryDefinition<T, TIdentifier>(DetachedCriteria.For<T>().Add(Restrictions.IdEq(id)))
                            .ToExecutableQuery(this, UnitOfWork);
        }

        public IExecutableQuery<T, TIdentifier> PrepareQuery(IQueryDefinition<T, TIdentifier> queryDefinition)
        {
            return queryDefinition.ToExecutableQuery(this, UnitOfWork);
        }

        public IList<T> Execute(QueryOver<T, T> queryOver)
        {
            return queryOver.GetExecutableQueryOver(UnitOfWork.Session).List();
        }

        public IList<T> GetAll()
        {
            return Execute(QueryOver.Of<T>());
        }

        public T Get(TIdentifier id)
        {
            return ById(id).Unique().Value;
        }
    }
}
